﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Optimization;

namespace NDF.Web.Optimization
{
    public class BundleWrapperFactory
    {
        private static Dictionary<object, List<BundleWrapper>> cache;

        protected internal static Dictionary<object, List<BundleWrapper>> BundleCache
        {
            get
            {
                if (BundleWrapperFactory.cache == null)
                {
                    BundleWrapperFactory.cache = new Dictionary<object, List<BundleWrapper>>();
                }
                return BundleWrapperFactory.cache;
            }
        }

        public static List<BundleWrapper> GetBundleWrapperList(object key)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            List<BundleWrapper> list = null;
            if (!BundleCache.TryGetValue(key, out list))
            {
                list = new List<BundleWrapper>();
                BundleCache.Add(key, list);
            }
            return list;
        }

        public static bool HasKey(object key)
        {
            return BundleCache.ContainsKey(key);
        }


        public static BundleWrapper GetBundleWrapper(object key, object bundlePath)
        {
            if (bundlePath == null)
            {
                throw new ArgumentNullException("bundlePath");
            }
            if (!(bundlePath is string || bundlePath is BundlePath))
            {
                throw new ArgumentException("参数 bundlePath 只能是 string 类型或者 BundlePath 类型对象。", "bundlePath");
            }
            BundlePath path = bundlePath is BundlePath ? bundlePath as BundlePath : new BundlePath(bundlePath as string);
            string virtualPath = path.VirtualPath;

            string directory = VirtualPathUtility.GetDirectory(virtualPath);
            string relative = VirtualPathUtility.ToAppRelative(directory);
            string extension = null;
            BundleType type = BundleUtils.GetBundleType(virtualPath, out extension);
            List<BundleWrapper> list = GetBundleWrapperList(key);

            BundleWrapper wrapper = list.LastOrDefault();
            if (wrapper == null || wrapper.Type != type ||
                !wrapper.Relative.Equals(relative, StringComparison.CurrentCultureIgnoreCase))
            {
                wrapper = new BundleWrapper();
                wrapper.Key = key;
                wrapper.OriginalPath = virtualPath;
                wrapper.Extension = extension;
                wrapper.Directory = directory;
                wrapper.Relative = relative;
                wrapper.Type = type;
                wrapper.VirtualPath = path.KeepPath ? virtualPath : (wrapper.Relative + Guid.NewGuid().ToString("N"));
                switch (wrapper.Type)
                {
                    case BundleType.JavaScript:
                        wrapper.Bundle = new ScriptBundle(wrapper.VirtualPath);
                        break;
                    case BundleType.Css:
                        wrapper.Bundle = new StyleBundle(wrapper.VirtualPath);
                        break;
                    case BundleType.NoType:
                    case BundleType.Unknown:
                        switch (path.Type)
                        {
                            case BundleType.JavaScript:
                                wrapper.Bundle = new ScriptBundle(wrapper.VirtualPath);
                                break;
                            case BundleType.Css:
                                wrapper.Bundle = new StyleBundle(wrapper.VirtualPath);
                                break;
                            case BundleType.NoType:
                            case BundleType.Unknown:
                                wrapper.Bundle = new Bundle(wrapper.VirtualPath);
                                break;
                        }
                        break;
                }
                list.Add(wrapper);
            }
            wrapper.Bundle.Include(virtualPath);
            return wrapper;
        }
    }
}
